#include "StdAfx.h"
#include "EndpointMap.h"
#include "PortIndex.h"

namespace RoomFW {

EndpointMap::EndpointMap(size_t size) :
	endpoints_(size),
	cs_()
{
}

EndpointMap::~EndpointMap(void)
{
	BOOST_FOREACH(EndpointList epl, endpoints_)
	{
		BOOST_FOREACH(IEndPointSP epsp, epl)
		{
			// If this assertion fails, an object is being destroyed before being unbound.
			ASSERT(0 == epsp);
		}
	}
}

size_t EndpointMap::size(void) const
{
	CriticalSectionGuard g(cs_);
	return endpoints_.size();
}

void EndpointMap::resize(size_t size)
{
	CriticalSectionGuard g(cs_);
	endpoints_.resize(size);
}

size_t EndpointMap::replicationSize(size_t port) const
{
	ASSERT(port < endpoints_.size());
	CriticalSectionGuard g(cs_);
	size_t retVal = 0;
	if (port < endpoints_.size())
	{
		retVal = endpoints_[port].size();
	}
	return retVal;
}

size_t EndpointMap::replicationCount(size_t port) const
{
	ASSERT(port < endpoints_.size());
	CriticalSectionGuard g(cs_);
	size_t retVal = 0;
	if (port < endpoints_.size())
	{
		BOOST_FOREACH(IEndPointSP ep, endpoints_[port])
		{
			if (0 != ep)
			{
				++retVal;
			}
		}
	}
	return retVal;
}

IEndPointSP EndpointMap::get(size_t port, size_t replication) const
{
	ASSERT(port < endpoints_.size());
	CriticalSectionGuard g(cs_);
	IEndPointSP retVal;
	if ((port < endpoints_.size()) &&
		(replication < endpoints_[port].size()))
	{
		retVal = endpoints_[port][replication];
	}
	return retVal;
}

size_t EndpointMap::add(size_t port, IEndPointSP endpoint)
{
	ASSERT(port < endpoints_.size());
	CriticalSectionGuard g(cs_);
	size_t retVal = PortIndex::REPLICATION_BROADCAST;
	if (port < endpoints_.size())
	{
		EndpointList& reps = endpoints_[port];
		for (EndpointList::iterator iEndpoint = reps.begin();
			 reps.end() != iEndpoint; ++iEndpoint)
		{
			if (0 == *iEndpoint)
			{
				*iEndpoint = endpoint;
				retVal = (std::distance(iEndpoint, reps.end()) - 1);
				break;
			}
		}
		if (PortIndex::REPLICATION_BROADCAST == retVal)
		{
			retVal = reps.size();
			reps.push_back(endpoint);
		}
	}
	return retVal;
}

bool EndpointMap::set(size_t port, size_t replication, IEndPointSP endpoint)
{
	ASSERT(port < endpoints_.size());
	bool retVal = false;
	CriticalSectionGuard g(cs_);
	if ((port < endpoints_.size()) && (replication < PortIndex::REPLICATION_BROADCAST))
	{
		EndpointList& reps = endpoints_[port];
		if (replication >= reps.size())
		{
			reps.resize(replication + 1);
		}
		IEndPointSP& ep = reps[replication];
		ASSERT(0 == ep);
		if (0 == ep)
		{
			ep = endpoint;
			retVal = true;
		}
	}
	return retVal;
}

bool EndpointMap::clear(size_t port, size_t replication)
{
	ASSERT(port < endpoints_.size());
	CriticalSectionGuard g(cs_);
	bool retVal = false;
	if ((port < endpoints_.size()) &&
		(replication < endpoints_[port].size()))
	{
		endpoints_[port][replication].reset();
		retVal = true;
	}
	return retVal;
}

void EndpointMap::clearAll(void)
{
	endpoints_.clear();
}

}
